/**
 * MP Software.
 */
package controllers;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import models.Deduction;
import models.Payment;
import models.Payroll;
import models.PayrollPeriod;
import models.Rate;
import play.mvc.Controller;
import service.CalculationResult;
import service.PaymentDeductionFacade;
import service.PayrollCalculatorFacade;
import service.PayrollRegisterService;
import service.RateResolver;
import controllers.views.DeductionTypeView;
import controllers.views.PaymentTypeView;
import controllers.views.Payslip;
import controllers.views.PayslipDeduction;
import controllers.views.PayslipPayment;

/**
 * @author Jeremiah John M. Macariola
 *
 */
public class PrintablePayslipView extends Controller {

	@Inject
	private static RateResolver rateResolver;

    @Inject
    private static PayrollCalculatorFacade payrollCalculatorFacade;

    @Inject
    private static PaymentDeductionFacade paymentDeductionFacade;

    @Inject
    private static PayrollRegisterService payrollRegisterService;

    public static void index(Long payrollPeriodId) {
        PayrollPeriod payPeriod = PayrollPeriod.findById(payrollPeriodId);
        String clientName = payPeriod.client.name;
        String payrollPeriod = getPayrollPeriod(payPeriod);
        List<Payslip> payslips = getPayslips(payPeriod);
        render(clientName, payrollPeriod, payslips);
    }

    private static String getPayrollPeriod(PayrollPeriod payPeriod) {
        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy");
        String startDate = sdf.format(payPeriod.fromDate);
        String endDate = sdf.format(payPeriod.toDate);
        return startDate + " - " + endDate;
    }

    private static List<Payslip> getPayslips(PayrollPeriod payPeriod) {
        List<Payroll> payrolls = payrollRegisterService.loadPayrolls(payPeriod);

        List<Payslip> payslips = new ArrayList<Payslip>();
        for (Payroll payroll : payrolls) {
            Payslip payslip = createPayslip(payroll);
            payslips.add(payslip);
        }

        return payslips;
    }

    private static Payslip createPayslip(Payroll payroll) {
        List<Payment> payments = Payment.find("payroll", payroll).fetch();
        List<Deduction> deductions = Deduction.find("payroll", payroll).fetch();

        String electronicId = payroll.employee.client.electronicId;
        Rate rate = rateResolver.getRate(electronicId);
        CalculationResult calcResult = payrollCalculatorFacade.calculate(
                electronicId, rate, payments, deductions);

        Payslip payslip = new Payslip();
        payslip.employeeName = payroll.employee.name;
        payslip.payments = createPayslipPayments(payments,
                rate, electronicId);
        payslip.deductions = createPayslipDeductions(deductions, electronicId);
        payslip.grossPay = calcResult.grossIncome;
        payslip.totalDeductions = calcResult.totalDeduction;
        payslip.takeHomePay = calcResult.netPay;
        payslip.rate = rate.value;

        return payslip;
    }

    private static List<PayslipPayment> createPayslipPayments(
            List<Payment> payments, Rate rate, String electronicId) {
        Map<String, BigDecimal> paymentMap = new HashMap<String, BigDecimal>();
        Map<String, Float> hoursMap = new HashMap<String, Float>();
        for (Payment payment : payments) {
            String paymentType = payment.paymentType;
            paymentMap.put(paymentType, payrollCalculatorFacade
                    .calculatePayment(electronicId, rate, payment));
            hoursMap.put(paymentType, payment.hours);
        }

        List<PayslipPayment> payslipPayments = new ArrayList<PayslipPayment>();
        for (PaymentTypeView paymentType : paymentDeductionFacade
                .getPaymentTypes(electronicId)) {
            String paymentTypeName = paymentType.name;
            Float hrs = null;

            if (!paymentType.label.endsWith("(value)")) {
                hrs = hoursMap.get(paymentTypeName);
            }

            PayslipPayment payslipPayment = new PayslipPayment(
                    paymentType.description, hrs,
                    paymentMap.get(paymentTypeName));
            payslipPayments.add(payslipPayment);
        }

        return payslipPayments;
    }

    private static List<PayslipDeduction> createPayslipDeductions(
            List<Deduction> deductions, String electronicId) {
        Map<String, BigDecimal> deductionMap = new HashMap<String, BigDecimal>();
        for (Deduction deduction : deductions) {
            deductionMap.put(deduction.deductionType, deduction.value);
        }

        List<PayslipDeduction> payslipDeductions = new ArrayList<PayslipDeduction>();
        for (DeductionTypeView deductionType : paymentDeductionFacade
                .getDeductionTypes(electronicId)) {
            String deductionTypeName = deductionType.name;
            PayslipDeduction payslipDeduction = new PayslipDeduction(
                    deductionType.label, deductionMap.get(deductionTypeName));
            payslipDeductions.add(payslipDeduction);
        }

        return payslipDeductions;
    }

}
